home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / Languages / Python 1.1 / Modules / cgen.py < prev    next >
Encoding:
Python Source  |  1994-08-01  |  13.0 KB  |  533 lines  |  [TEXT/R*ch]

  1. ########################################################################
  2. # Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
  3. # Amsterdam, The Netherlands.
  4. #                         All Rights Reserved
  5. # Permission to use, copy, modify, and distribute this software and its 
  6. # documentation for any purpose and without fee is hereby granted, 
  7. # provided that the above copyright notice appear in all copies and that
  8. # both that copyright notice and this permission notice appear in 
  9. # supporting documentation, and that the names of Stichting Mathematisch
  10. # Centrum or CWI not be used in advertising or publicity pertaining to
  11. # distribution of the software without specific, written prior permission.
  12. # STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
  13. # THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  14. # FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
  15. # FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  16. # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  17. # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  18. # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  19. ########################################################################
  20.  
  21. # Python script to parse cstubs file for gl and generate C stubs.
  22. # usage: python cgen.py <cstubs >glmodule.c
  23. #
  24. # NOTE: You  must first make a python binary without the "GL" option
  25. #    before you can run this, when building Python for the first time.
  26. #    See comments in the Makefile.
  27. #
  28. # XXX BUG return arrays generate wrong code
  29. # XXX need to change error returns into gotos to free mallocked arrays
  30.  
  31.  
  32. import string
  33. import sys
  34.  
  35.  
  36. # Function to print to stderr
  37. #
  38. def err(args):
  39.     savestdout = sys.stdout
  40.     try:
  41.         sys.stdout = sys.stderr
  42.         for i in args:
  43.             print i,
  44.         print
  45.     finally:
  46.         sys.stdout = savestdout
  47.  
  48.  
  49. # The set of digits that form a number
  50. #
  51. digits = '0123456789'
  52.  
  53.  
  54. # Function to extract a string of digits from the front of the string.
  55. # Returns the leading string of digits and the remaining string.
  56. # If no number is found, returns '' and the original string.
  57. #
  58. def getnum(s):
  59.     n = ''
  60.     while s and s[0] in digits:
  61.         n = n + s[0]
  62.         s = s[1:]
  63.     return n, s
  64.  
  65.  
  66. # Function to check if a string is a number
  67. #
  68. def isnum(s):
  69.     if not s: return 0
  70.     for c in s:
  71.         if not c in digits: return 0
  72.     return 1
  73.  
  74.  
  75. # Allowed function return types
  76. #
  77. return_types = ['void', 'short', 'long']
  78.  
  79.  
  80. # Allowed function argument types
  81. #
  82. arg_types = ['char', 'string', 'short', 'u_short', 'float', 'long', 'double']
  83.  
  84.  
  85. # Need to classify arguments as follows
  86. #    simple input variable
  87. #    simple output variable
  88. #    input array
  89. #    output array
  90. #    input giving size of some array
  91. #
  92. # Array dimensions can be specified as follows
  93. #    constant
  94. #    argN
  95. #    constant * argN
  96. #    retval
  97. #    constant * retval
  98. #
  99. # The dimensions given as constants * something are really
  100. # arrays of points where points are 2- 3- or 4-tuples
  101. #
  102. # We have to consider three lists:
  103. #    python input arguments
  104. #    C stub arguments (in & out)
  105. #    python output arguments (really return values)
  106. #
  107. # There is a mapping from python input arguments to the input arguments
  108. # of the C stub, and a further mapping from C stub arguments to the
  109. # python return values
  110.  
  111.  
  112. # Exception raised by checkarg() and generate()
  113. #
  114. arg_error = 'bad arg'
  115.  
  116.  
  117. # Function to check one argument.
  118. # Arguments: the type and the arg "name" (really mode plus subscript).
  119. # Raises arg_error if something's wrong.
  120. # Return type, mode, factor, rest of subscript; factor and rest may be empty.
  121. #
  122. def checkarg(type, arg):
  123.     #
  124.     # Turn "char *x" into "string x".
  125.     #
  126.     if type == 'char' and arg[0] == '*':
  127.         type = 'string'
  128.         arg = arg[1:]
  129.     #
  130.     # Check that the type is supported.
  131.     #
  132.     if type not in arg_types:
  133.         raise arg_error, ('bad type', type)
  134.     if type[:2] == 'u_':
  135.         type = 'unsigned ' + type[2:]
  136.     #
  137.     # Split it in the mode (first character) and the rest.
  138.     #
  139.     mode, rest = arg[:1], arg[1:]
  140.     #
  141.     # The mode must be 's' for send (= input) or 'r' for return argument.
  142.     #
  143.     if mode not in ('r', 's'):
  144.         raise arg_error, ('bad arg mode', mode)
  145.     #
  146.     # Is it a simple argument: if so, we are done.
  147.     #
  148.     if not rest:
  149.         return type, mode, '', ''
  150.     #    
  151.     # Not a simple argument; must be an array.
  152.     # The 'rest' must be a subscript enclosed in [ and ].
  153.     # The subscript must be one of the following forms,
  154.     # otherwise we don't handle it (where N is a number):
  155.     #    N
  156.     #    argN
  157.     #    retval
  158.     #    N*argN
  159.     #    N*retval
  160.     #
  161.     if rest[:1] <> '[' or rest[-1:] <> ']':
  162.         raise arg_error, ('subscript expected', rest)
  163.     sub = rest[1:-1]
  164.     #
  165.     # Is there a leading number?
  166.     #
  167.     num, sub = getnum(sub)
  168.     if num:
  169.         # There is a leading number
  170.         if not sub:
  171.             # The subscript is just a number
  172.             return type, mode, num, ''
  173.         if sub[:1] == '*':
  174.             # There is a factor prefix
  175.             sub = sub[1:]
  176.         else:
  177.             raise arg_error, ('\'*\' expected', sub)
  178.     if sub == 'retval':
  179.         # size is retval -- must be a reply argument
  180.         if mode <> 'r':
  181.             raise arg_error, ('non-r mode with [retval]', mode)
  182.     elif not isnum(sub) and (sub[:3] <> 'arg' or not isnum(sub[3:])):
  183.         raise arg_error, ('bad subscript', sub)
  184.     #
  185.     return type, mode, num, sub
  186.  
  187.  
  188. # List of functions for which we have generated stubs
  189. #
  190. functions = []
  191.  
  192.  
  193. # Generate the stub for the given function, using the database of argument
  194. # information build by successive calls to checkarg()
  195. #
  196. def generate(type, func, database):
  197.     #
  198.     # Check that we can handle this case:
  199.     # no variable size reply arrays yet
  200.     #
  201.     n_in_args = 0
  202.     n_out_args = 0
  203.     #
  204.     for a_type, a_mode, a_factor, a_sub in database:
  205.         if a_mode == 's':
  206.             n_in_args = n_in_args + 1
  207.         elif a_mode == 'r':
  208.             n_out_args = n_out_args + 1
  209.         else:
  210.             # Can't happen
  211.             raise arg_error, ('bad a_mode', a_mode)
  212.         if (a_mode == 'r' and a_sub) or a_sub == 'retval':
  213.             e = 'Function', func, 'too complicated:'
  214.             err(e + (a_type, a_mode, a_factor, a_sub))
  215.             print '/* XXX Too complicated to generate code for */'
  216.             return
  217.     #
  218.     functions.append(func)
  219.     #
  220.     # Stub header
  221.     #
  222.     print
  223.     print 'static object *'
  224.     print 'gl_' + func + '(self, args)'
  225.     print '\tobject *self;'
  226.     print '\tobject *args;'
  227.     print '{'
  228.     #
  229.     # Declare return value if any
  230.     #
  231.     if type <> 'void':
  232.         print '\t' + type, 'retval;'
  233.     #
  234.     # Declare arguments
  235.     #
  236.     for i in range(len(database)):
  237.         a_type, a_mode, a_factor, a_sub = database[i]
  238.         print '\t' + a_type,
  239.         brac = ket = ''
  240.         if a_sub and not isnum(a_sub):
  241.             if a_factor:
  242.                 brac = '('
  243.                 ket = ')'
  244.             print brac + '*',
  245.         print 'arg' + `i+1` + ket,
  246.         if a_sub and isnum(a_sub):
  247.             print '[', a_sub, ']',
  248.         if a_factor:
  249.             print '[', a_factor, ']',
  250.         print ';'
  251.     #
  252.     # Find input arguments derived from array sizes
  253.     #
  254.     for i in range(len(database)):
  255.         a_type, a_mode, a_factor, a_sub = database[i]
  256.         if a_mode == 's' and a_sub[:3] == 'arg' and isnum(a_sub[3:]):
  257.             # Sending a variable-length array
  258.             n = eval(a_sub[3:])
  259.             if 1 <= n <= len(database):
  260.                 b_type, b_mode, b_factor, b_sub = database[n-1]
  261.                 if b_mode == 's':
  262.                     database[n-1] = b_type, 'i', a_factor, `i`
  263.                     n_in_args = n_in_args - 1
  264.     #
  265.     # Assign argument positions in the Python argument list
  266.     #
  267.     in_pos = []
  268.     i_in = 0
  269.     for i in range(len(database)):
  270.         a_type, a_mode, a_factor, a_sub = database[i]
  271.         if a_mode == 's':
  272.             in_pos.append(i_in)
  273.             i_in = i_in + 1
  274.         else:
  275.             in_pos.append(-1)
  276.     #
  277.     # Get input arguments
  278.     #
  279.     for i in range(len(database)):
  280.         a_type, a_mode, a_factor, a_sub = database[i]
  281.         if a_type[:9] == 'unsigned ':
  282.             xtype = a_type[9:]
  283.         else:
  284.             xtype = a_type
  285.         if a_mode == 'i':
  286.             #
  287.             # Implicit argument;
  288.             # a_factor is divisor if present,
  289.             # a_sub indicates which arg (`database index`)
  290.             #
  291.             j = eval(a_sub)
  292.             print '\tif',
  293.             print '(!geti' + xtype + 'arraysize(args,',
  294.             print `n_in_args` + ',',
  295.             print `in_pos[j]` + ',',
  296.             if xtype <> a_type:
  297.                 print '('+xtype+' *)',
  298.             print '&arg' + `i+1` + '))'
  299.             print '\t\treturn NULL;'
  300.             if a_factor:
  301.                 print '\targ' + `i+1`,
  302.                 print '= arg' + `i+1`,
  303.                 print '/', a_factor + ';'
  304.         elif a_mode == 's':
  305.             if a_sub and not isnum(a_sub):
  306.                 # Allocate memory for varsize array
  307.                 print '\tif ((arg' + `i+1`, '=',
  308.                 if a_factor:
  309.                     print '('+a_type+'(*)['+a_factor+'])',
  310.                 print 'NEW(' + a_type, ',',
  311.                 if a_factor:
  312.                     print a_factor, '*',
  313.                 print a_sub, ')) == NULL)'
  314.                 print '\t\treturn err_nomem();'
  315.             print '\tif',
  316.             if a_factor or a_sub: # Get a fixed-size array array
  317.                 print '(!geti' + xtype + 'array(args,',
  318.                 print `n_in_args` + ',',
  319.                 print `in_pos[i]` + ',',
  320.                 if a_factor: print a_factor,
  321.                 if a_factor and a_sub: print '*',
  322.                 if a_sub: print a_sub,
  323.                 print ',',
  324.                 if (a_sub and a_factor) or xtype <> a_type:
  325.                     print '('+xtype+' *)',
  326.                 print 'arg' + `i+1` + '))'
  327.             else: # Get a simple variable
  328.                 print '(!geti' + xtype + 'arg(args,',
  329.                 print `n_in_args` + ',',
  330.                 print `in_pos[i]` + ',',
  331.                 if xtype <> a_type:
  332.                     print '('+xtype+' *)',
  333.                 print '&arg' + `i+1` + '))'
  334.             print '\t\treturn NULL;'
  335.     #
  336.     # Begin of function call
  337.     #
  338.     if type <> 'void':
  339.         print '\tretval =', func + '(',
  340.     else:
  341.         print '\t' + func + '(',
  342.     #
  343.     # Argument list
  344.     #
  345.     for i in range(len(database)):
  346.         if i > 0: print ',',
  347.         a_type, a_mode, a_factor, a_sub = database[i]
  348.         if a_mode == 'r' and not a_factor:
  349.             print '&',
  350.         print 'arg' + `i+1`,
  351.     #
  352.     # End of function call
  353.     #
  354.     print ');'
  355.     #
  356.     # Free varsize arrays
  357.     #
  358.     for i in range(len(database)):
  359.         a_type, a_mode, a_factor, a_sub = database[i]
  360.         if a_mode == 's' and a_sub and not isnum(a_sub):
  361.             print '\tDEL(arg' + `i+1` + ');'
  362.     #
  363.     # Return
  364.     #
  365.     if n_out_args:
  366.         #
  367.         # Multiple return values -- construct a tuple
  368.         #
  369.         if type <> 'void':
  370.             n_out_args = n_out_args + 1
  371.         if n_out_args == 1:
  372.             for i in range(len(database)):
  373.                 a_type, a_mode, a_factor, a_sub = database[i]
  374.                 if a_mode == 'r':
  375.                     break
  376.             else:
  377.                 raise arg_error, 'expected r arg not found'
  378.             print '\treturn',
  379.             print mkobject(a_type, 'arg' + `i+1`) + ';'
  380.         else:
  381.             print '\t{ object *v = newtupleobject(',
  382.             print n_out_args, ');'
  383.             print '\t  if (v == NULL) return NULL;'
  384.             i_out = 0
  385.             if type <> 'void':
  386.                 print '\t  settupleitem(v,',
  387.                 print `i_out` + ',',
  388.                 print mkobject(type, 'retval') + ');'
  389.                 i_out = i_out + 1
  390.             for i in range(len(database)):
  391.                 a_type, a_mode, a_factor, a_sub = database[i]
  392.                 if a_mode == 'r':
  393.                     print '\t  settupleitem(v,',
  394.                     print `i_out` + ',',
  395.                     s = mkobject(a_type, 'arg' + `i+1`)
  396.                     print s + ');'
  397.                     i_out = i_out + 1
  398.             print '\t  return v;'
  399.             print '\t}'
  400.     else:
  401.         #
  402.         # Simple function return
  403.         # Return None or return value
  404.         #
  405.         if type == 'void':
  406.             print '\tINCREF(None);'
  407.             print '\treturn None;'
  408.         else:
  409.             print '\treturn', mkobject(type, 'retval') + ';'
  410.     #
  411.     # Stub body closing brace
  412.     #
  413.     print '}'
  414.  
  415.  
  416. # Subroutine to return a function call to mknew<type>object(<arg>)
  417. #
  418. def mkobject(type, arg):
  419.     if type[:9] == 'unsigned ':
  420.         type = type[9:]
  421.         return 'mknew' + type + 'object((' + type + ') ' + arg + ')'
  422.     return 'mknew' + type + 'object(' + arg + ')'
  423.  
  424.  
  425. defined_archs = []
  426.  
  427. # usage: cgen [ -Dmach ... ] [ file ]
  428. for arg in sys.argv[1:]:
  429.     if arg[:2] == '-D':
  430.         defined_archs.append(arg[2:])
  431.     else:
  432.         # Open optional file argument
  433.         sys.stdin = open(arg, 'r')
  434.  
  435.  
  436. # Input line number
  437. lno = 0
  438.  
  439.  
  440. # Input is divided in two parts, separated by a line containing '%%'.
  441. #    <part1>        -- literally copied to stdout
  442. #    <part2>        -- stub definitions
  443.  
  444. # Variable indicating the current input part.
  445. #
  446. part = 1
  447.  
  448. # Main loop over the input
  449. #
  450. while 1:
  451.     try:
  452.         line = raw_input()
  453.     except EOFError:
  454.         break
  455.     #
  456.     lno = lno+1
  457.     words = string.split(line)
  458.     #
  459.     if part == 1:
  460.         #
  461.         # In part 1, copy everything literally
  462.         # except look for a line of just '%%'
  463.         #
  464.         if words == ['%%']:
  465.             part = part + 1
  466.         else:
  467.             #
  468.             # Look for names of manually written
  469.             # stubs: a single percent followed by the name
  470.             # of the function in Python.
  471.             # The stub name is derived by prefixing 'gl_'.
  472.             #
  473.             if words and words[0][0] == '%':
  474.                 func = words[0][1:]
  475.                 if (not func) and words[1:]:
  476.                     func = words[1]
  477.                 if func:
  478.                     functions.append(func)
  479.             else:
  480.                 print line
  481.         continue
  482.     if not words:
  483.         continue        # skip empty line
  484.     elif words[0] == 'if':
  485.         # if XXX rest
  486.         # if !XXX rest
  487.         if words[1][0] == '!':
  488.             if words[1][1:] in defined_archs:
  489.                 continue
  490.         elif words[1] not in defined_archs:
  491.             continue
  492.         words = words[2:]
  493.     if words[0] == '#include':
  494.         print line
  495.     elif words[0][:1] == '#':
  496.         pass            # ignore comment
  497.     elif words[0] not in return_types:
  498.         err('Line', lno, ': bad return type :', words[0])
  499.     elif len(words) < 2:
  500.         err('Line', lno, ': no funcname :', line)
  501.     else:
  502.         if len(words) % 2 <> 0:
  503.             err('Line', lno, ': odd argument list :', words[2:])
  504.         else:
  505.             database = []
  506.             try:
  507.                 for i in range(2, len(words), 2):
  508.                     x = checkarg(words[i], words[i+1])
  509.                     database.append(x)
  510.                 print
  511.                 print '/*',
  512.                 for w in words: print w,
  513.                 print '*/'
  514.                 generate(words[0], words[1], database)
  515.             except arg_error, msg:
  516.                 err('Line', lno, ':', msg)
  517.  
  518.  
  519. print
  520. print 'static struct methodlist gl_methods[] = {'
  521. for func in functions:
  522.     print '\t{"' + func + '", gl_' + func + '},'
  523. print '\t{NULL, NULL} /* Sentinel */'
  524. print '};'
  525. print
  526. print 'initgl()'
  527. print '{'
  528. print '\tinitmodule("gl", gl_methods);'
  529. print '}'
  530.